﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Xml;
using System.Net;

namespace soma.Services
{
    public class SynonymsProvider
    {
        private const string ThesaurusAPIKey = "u9U8JKaOitVKHBOahvUs";
        private const string Stands4APIKey = "HNE22zbUpwr9iDfx";
        private const string Stands4UID = "3098";

        private static SynonymsProvider instance = null;
        private static Object locker = new Object();

        private static Dictionary<string, List<string>> synonymsDictionary;

        private SynonymsProvider()
        {
            synonymsDictionary = new Dictionary<string, List<string>>();
        }

        public static SynonymsProvider Instance
        {
            get
            {
                if (instance == null)
                {
                    lock (locker)
                    {
                        if (instance == null)
                        {
                            instance = new SynonymsProvider();
                        }
                    }
                }

                return instance;
            }
        }

        public List<string> ProvideSynonyms(string word, int count)
        {
            List<string> synList = new List<string>();

            if (synonymsDictionary.ContainsKey(word) && count <= synonymsDictionary[word].Count)
            {
                return synonymsDictionary[word].ToList<string>().GetRange(0, Math.Min(count, synonymsDictionary[word].Count));
            }
            else
            {
                Dictionary<string, int> joinDictionaries = new Dictionary<string, int>();

                Dictionary<string, int> stands4Synonyms = new Dictionary<string, int>();
                word = word.Replace(" ", "%20");
                try
                {
                    stands4Synonyms = ProvideStands4Synonyms(word);
                }
                catch (WebException exc)
                {
                    Console.Error.WriteLine(exc.Message);
                }

                Dictionary<string, int> thesaurusSynonyms = new Dictionary<string, int>();
                try
                {
                    thesaurusSynonyms = ProvideThesaurusSynonyms(word);
                }
                catch (WebException exc)
                {
                    Console.Error.WriteLine(exc.Message);
                }

                if (stands4Synonyms.Count > 0)
                {
                    if (thesaurusSynonyms.Count > 0)
                    {
                        synList = stands4Synonyms.Keys.Intersect(thesaurusSynonyms.Keys).ToList<string>();
                        for (int i = 0; i < synList.Count; i++)
                        {
                            joinDictionaries.Add(synList[i], stands4Synonyms[synList[i]] + thesaurusSynonyms[synList[i]]);
                        }
                    }
                    else
                    {
                        synList = stands4Synonyms.Keys.ToList<string>();
                        for (int i = 0; i < synList.Count; i++)
                        {
                            joinDictionaries.Add(synList[i], stands4Synonyms[synList[i]]);
                        }
                    }
                }
                else
                {
                    synList = thesaurusSynonyms.Keys.ToList<string>();
                    for (int i = 0; i < synList.Count; i++)
                    {
                        joinDictionaries.Add(synList[i], thesaurusSynonyms[synList[i]]);
                    }
                }

                synList = new List<string>();
                foreach (KeyValuePair<string, int> item in joinDictionaries.OrderByDescending(key => key.Value))
                {
                    synList.Add(item.Key);
                }
                synonymsDictionary[word] = synList;
            }
            return synList.GetRange(0, Math.Min(count, synList.Count));
        }

        private Dictionary<string, int> ProvideStands4Synonyms(string word)
        {
            Dictionary<string, int> synonyms = new Dictionary<string, int>();

            string url = "http://www.stands4.com/services/v2/syno.php?uid=" + Stands4UID + "&tokenid=" + Stands4APIKey + "&word=" + word;

            // create the GET request
            System.Net.HttpWebRequest webRequest = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(url);
            webRequest.Method = "GET";

            // GET the data
            System.Net.HttpWebResponse webResponse = (System.Net.HttpWebResponse)webRequest.GetResponse();

            //Load response stream into XMLReader
            XmlTextReader xmlReader = new XmlTextReader(webResponse.GetResponseStream());

            string syn = null;
            List<string> synList = new List<string>();
            while (xmlReader.Read())
            {
                if (xmlReader.NodeType == XmlNodeType.Element)
                {
                    if (xmlReader.Name == "synonyms" || xmlReader.Name == "term")
                    {
                        syn = xmlReader.ReadElementContentAsString();
                        synList.AddRange(syn.Split(new string[] { ", " }, StringSplitOptions.RemoveEmptyEntries).ToList<string>());
                    }
                }

            }

            for (int i = 0; i < synList.Count; i++)
            {
                if (synonyms.ContainsKey(synList[i]))
                {
                    synonyms[synList[i]] += 1;
                }
                else
                {
                    synonyms.Add(synList[i], 1);
                }
            }

            return synonyms;
        }

        private Dictionary<string, int> ProvideThesaurusSynonyms(string word)
        {
            Dictionary<string, int> synonyms = new Dictionary<string, int>();

            string url = "http://thesaurus.altervista.org/thesaurus/v1?word=" + word + "&language=en_US&key=" + ThesaurusAPIKey + "&output=xml";

            // create the GET request
            System.Net.HttpWebRequest webRequest = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(url);
            webRequest.Method = "GET";

            // GET the data
            System.Net.HttpWebResponse webResponse = (System.Net.HttpWebResponse)webRequest.GetResponse();

            //Load response stream into XMLReader
            XmlTextReader xmlReader = new XmlTextReader(webResponse.GetResponseStream());

            string syn = null;
            List<string> synList = new List<string>();
            while (xmlReader.Read())
            {
                if (xmlReader.NodeType == XmlNodeType.Element)
                {
                    if (xmlReader.Name == "synonyms")
                    {
                        syn = xmlReader.ReadElementContentAsString();
                        synList.AddRange(syn.Split('|').ToList<string>());
                    }
                }

            }

            synList.RemoveAll(IsAntonym);
            for (int i = 0; i < synList.Count; i++)
            {
                if (synList[i].Contains("("))
                {
                    int begin = synList[i].IndexOf("(");
                    int end = synList[i].LastIndexOf(")");
                    synList[i] = synList[i].Remove(begin, end - begin + 1).TrimEnd();
                }
            }

            for (int i = 0; i < synList.Count; i++)
            {
                if (synonyms.ContainsKey(synList[i]))
                {
                    synonyms[synList[i]] += 1;
                }
                else
                {
                    synonyms.Add(synList[i], 1);
                }
            }

            return synonyms;
        }

        private bool IsAntonym(string synonym)
        {
            return synonym.Contains("antonym");
        }
    }
}